//
//  DropDownMenu.swift
//  DropDownMenu
//
//  Created by 在成长开发 on 2024/6/24.
//  Copyright © 2024 刘爽. All rights reserved.
//

import UIKit

public protocol DropDownMenuDelegate {
    func dropDownMenu(_ menu: DropDownMenu, didClickAt indexPath: IndexPath)

    func dropDownMenuHide(_ menu: DropDownMenu)

    func dropDownMenuRegisterCustomClass(_ menu: DropDownMenu) -> String?
    func dropDownMenuRegisterCustomNib(_ menu: DropDownMenu) -> String?

    func dropDownMenu(_ menu: DropDownMenu, useCustomItem collectionView: UICollectionView, at indexPath: IndexPath) -> UICollectionViewCell?

}

public extension DropDownMenuDelegate {

    func dropDownMenuRegisterCustomClass(_ menu: DropDownMenu) -> String? {
        return nil
    }

    func dropDownMenuRegisterCustomNib(_ menu: DropDownMenu) -> String? {
        return nil
    }

    func dropDownMenu(_ menu: DropDownMenu, useCustomItem collectionView: UICollectionView, at indexPath: IndexPath) -> UICollectionViewCell? {
        return nil
    }

    func dropDownMenuHide(_ menu: DropDownMenu) {

    }
}

public final class DropDownMenu: UIView {

    private lazy var containerView: UIView = {
        let view = UIView()
        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleClickBackground)))
        return view
    }()

    private lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let view = UICollectionView(frame: CGRect(x: 0, y: 0, width: 100, height: 100), collectionViewLayout: layout)
        view.register(DropDownMenuCell.self, forCellWithReuseIdentifier: "DropDownMenuCell")
        view.delegate = self
        view.dataSource = self

        view.backgroundView = UIImageView()

        return view
    }()

    public func menuBackgroundView() -> UIImageView {
        return collectionView.backgroundView as! UIImageView
    }

    private var titles: [String] = []
    private var images: [String]?

    public init(titles: [String], images: [String]? = nil) {
        self.titles = titles
        self.images = images
        if images == nil {
            self.menuType = .title
        } else {
            self.menuType = .leftImage
        }
        self.showFromPoint = .zero
        super.init(frame: .zero)

        self.setupSubviews()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupSubviews() {
        backgroundColor = .clear
        self.addSubview(containerView)
        self.addSubview(collectionView)
    }

    public var delegate: DropDownMenuDelegate? {
        didSet {
            if let className = delegate?.dropDownMenuRegisterCustomClass(self) {
                collectionView.register(NSClassFromString(className), forCellWithReuseIdentifier: className)
            } else if let nibName = delegate?.dropDownMenuRegisterCustomNib(self) {
                collectionView.register(UINib(nibName: nibName, bundle: nil), forCellWithReuseIdentifier: nibName)
            }
        }
    }
    public var showFromPoint: CGPoint {
        didSet {
            // update frame
            self.setNeedsLayout()
            self.layoutIfNeeded()
        }
    }

    public enum ShowFromType {
        case leftTop
        case leftCenter
        case leftBottom
        case rightTop
        case rightCenter
        case rightBottom
        case centerTop
        case centerBottom
    }
    public var showFrom: ShowFromType = .leftTop {
        didSet {
            // update frame
            self.setNeedsLayout()
            self.layoutIfNeeded()
        }
    }

    public var menuSize: CGSize = .zero {
        didSet {
            // update frame
            self.setNeedsLayout()
            self.layoutIfNeeded()
        }
    }
    public var menuInset: UIEdgeInsets = .zero {
        didSet {
            collectionView.reloadData()
        }
    }
    public var menuItemHeight: CGFloat = 44.0 {
        didSet {
            collectionView.reloadData()
        }
    }

    public var menuType: MenuType = .title {
        didSet {
            collectionView.reloadData()
        }
    }

    public var selectedBackgroundColor: UIColor = .clear {
        didSet {
            collectionView.reloadData()
        }
    }
    public var selectedImage: UIImage? {
        didSet {
            if selectedImage != nil {
                if self.menuType == .title {
                    if images != nil {
                        self.menuType = .leftImage
                    } else {
                        self.menuType = .rightImage
                    }
                }
            }
            collectionView.reloadData()
        }
    }
    public var textColor: UIColor = .black {
        didSet {
            collectionView.reloadData()
        }
    }
    public var selectedTextColor: UIColor? {
        didSet {
            collectionView.reloadData()
        }
    }
    public var textFont: UIFont = .systemFont(ofSize: 14) {
        didSet {
            collectionView.reloadData()
        }
    }
    public var selectedTextFont: UIFont? {
        didSet {
            collectionView.reloadData()
        }
    }
    public var textAlignment: NSTextAlignment = .left {
        didSet {
            collectionView.reloadData()
        }
    }
    public var contentLeft: CGFloat = 0
    public var contentRight: CGFloat = 0
    public var textImageSpace: CGFloat = 8

    public var selectedIndex: IndexPath?
    public var showBackground: Bool = true
    public var autoHide: Bool = true

    public var showAnimated: Bool = true
    public func show() {
        show(showAnimated)
    }
    public func show(_ animated: Bool) {
        guard let window: UIWindow = DropDownMenu.currentWindow() else { return }
        show(in: window, animated: animated)

    }
    public func show(in view: UIView) {
        show(in: view, animated: showAnimated)
    }
    public func show(in view: UIView, animated: Bool) {
        collectionView.alpha = 1
        frame = view.bounds
        view.addSubview(self)

        if animated {
            if showFrom == .centerTop || showFrom == .centerBottom {
                collectionView.transform = CGAffineTransformMakeScale(1.0, 0)
            } else if showFrom == .leftCenter || showFrom == .rightCenter {
                collectionView.transform = CGAffineTransformMakeScale(0, 1.0)
            } else {
                collectionView.transform = CGAffineTransformMakeScale(0, 0)
            }
            UIViewPropertyAnimator(duration: DropDownMenu.kAnimationDuration, curve: .easeInOut) {[weak self] in
                guard let self = self else { return }
                self.collectionView.transform = CGAffineTransformIdentity
                if self.showBackground {
                    self.containerView.isHidden = false
                }
            }.startAnimation()
        } else {
            collectionView.transform = CGAffineTransformIdentity
            if showBackground {
                containerView.isHidden = false
            }
        }

    }

    public var hideAnimated: Bool = true
    public func hide() {
        hide(hideAnimated)
    }
    public func hide(_ animated: Bool, completion: (()-> Void)? = nil) {
        var targetTransform: CGAffineTransform
        if showFrom == .centerTop || showFrom == .centerBottom {
            targetTransform = CGAffineTransformMakeScale(1.0, 0)
        } else if showFrom == .leftCenter || showFrom == .rightCenter {
            targetTransform = CGAffineTransformMakeScale(0, 1.0)
        } else {
            targetTransform = CGAffineTransformMakeScale(0, 0)
        }
        if animated {
            let animator = UIViewPropertyAnimator(duration: DropDownMenu.kAnimationDuration, curve: .easeInOut) {[weak self] in
                guard let self = self else { return }

                self.collectionView.transform = targetTransform
                if showBackground {
                    self.containerView.isHidden = true
                }
            }
            animator.addCompletion {[weak self] _ in
                guard let self = self else { return }
                self.removeFromSuperview()
                completion?()
            }
            animator.startAnimation()
        } else {
            collectionView.transform = targetTransform
            if showBackground {
                containerView.isHidden = false
            }
            removeFromSuperview()
            completion?()
        }

    }

    @objc func handleClickBackground() {
        self.hide()
        self.delegate?.dropDownMenuHide(self)
    }

    public override func layoutSubviews() {
        super.layoutSubviews()
        if let superview = self.superview {
            frame = superview.bounds
        }
        if showBackground {
            containerView.frame = self.bounds
            containerView.isHidden = false
        } else {
            containerView.isHidden = true
        }

        var frame: CGRect = .zero
        if CGSizeEqualToSize(menuSize, .zero) {
            var height: CGFloat = menuItemHeight * CGFloat(titles.count) + menuInset.top + menuInset.bottom
            if let superview = superview {
                if height > superview.frame.height {
                    height = superview.frame.height - 100;
                }
            } else {
                if let window = DropDownMenu.currentWindow(), height > window.frame.height {
                    height = window.frame.height - 100
                }
            }
            frame.size = CGSize(width: 120, height: height)
        } else {
            collectionView.isScrollEnabled = menuItemHeight * CGFloat(titles.count) + menuInset.top + menuInset.bottom > menuSize.height

            frame.size = CGSize(width: menuSize.width, height: menuSize.height)
        }

        var anchorPoint: CGPoint
        switch showFrom {
        case .leftTop:
            frame.origin = showFromPoint
            anchorPoint = .zero
        case .leftCenter:
            frame.origin = CGPoint(x: showFromPoint.x, y: showFromPoint.y - frame.size.height / 2)
            anchorPoint = CGPoint(x: 0, y: 0.5)
        case .leftBottom:
            frame.origin = CGPoint(x: showFromPoint.x, y: showFromPoint.y - frame.size.height)
            anchorPoint = CGPoint(x: 0, y: 1)
        case .rightTop:
            frame.origin = CGPoint(x: showFromPoint.x - frame.size.width, y: showFromPoint.y)
            anchorPoint = CGPoint(x: 1, y: 0)
        case .rightCenter:
            frame.origin = CGPoint(x: showFromPoint.x - frame.size.width, y: showFromPoint.y - frame.size.height / 2)
            anchorPoint = CGPoint(x: 1, y: 0.5)
        case .rightBottom:
            frame.origin = CGPoint(x: showFromPoint.x - frame.size.width, y: showFromPoint.y - frame.size.height)
            anchorPoint = CGPoint(x: 1, y: 1)
        case .centerTop:
            frame.origin = CGPoint(x: showFromPoint.x - frame.size.width / 2, y: showFromPoint.y)
            anchorPoint = CGPoint(x: 0.5, y: 0)
        case .centerBottom:
            frame.origin = CGPoint(x: showFromPoint.x - frame.size.width / 2, y: showFromPoint.y - frame.size.height)
            anchorPoint = CGPoint(x: 0.5, y: 1)
        }
        collectionView.layer.position = showFromPoint
        collectionView.layer.anchorPoint = anchorPoint
        collectionView.frame = frame

    }


    class func currentWindow() -> UIWindow? {
        var keyWindow: UIWindow?

        if #available(iOS 13.0, *) {
            keyWindow = UIApplication.shared.connectedScenes
                .filter({ $0.activationState == .foregroundActive })
//                .map({ $0 as? UIWindowScene })
                .compactMap({ $0 as? UIWindowScene })
//                .compactMap({ $0 })
                .first?.windows
                .filter({$0.isKeyWindow}).first
        }
        if keyWindow == nil {
            keyWindow = UIApplication.shared.windows.filter({$0.isKeyWindow}).first
        }

        return keyWindow
    }
}



extension DropDownMenu: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    // MARK: - UICollectionViewDelegateFlowLayout
    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return self.menuInset
    }

    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: CGRectGetWidth(collectionView.bounds) - self.menuInset.left - self.menuInset.right, height: self.menuItemHeight)
    }

    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    // MARK: - UICollectionViewDataSource
    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return titles.count
    }

    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        if let customCell = self.delegate?.dropDownMenu(self, useCustomItem: collectionView, at: indexPath) {
            return customCell
        }

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DropDownMenuCell", for: indexPath) as! DropDownMenuCell
        cell.menuType = self.menuType
        if let imageName = self.images?[indexPath.item] {
            cell.iconImage.image = UIImage(named: imageName)
        } else {
            cell.iconImage.image = nil
        }
        cell.contentLeft = self.contentLeft
        cell.contentRight = self.contentRight
        cell.textImageSpace = self.textImageSpace

        cell.titleLabel.font = self.textFont
        cell.titleLabel.textColor = self.textColor
        if (self.selectedIndex == indexPath) {
            if let selectedIcon = selectedImage {
                cell.iconImage.image = selectedIcon
            }
            cell.titleLabel.font = self.selectedTextFont
            cell.titleLabel.textColor = self.selectedTextColor
        }
        cell.titleLabel.textAlignment = self.textAlignment
        cell.titleLabel.text = titles[indexPath.item]

        cell.backgroundView?.backgroundColor = self.selectedBackgroundColor

        return cell
    }
    
    static let kAnimationDuration: TimeInterval = 0.25
    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//        if self.selectedIndexs.contains(where: {$0 == indexPath }) {
//            self.selectedIndexs.removeAll(where: {$0 == indexPath })
//        } else {
//            self.selectedIndexs.append(indexPath)
//        }
        self.selectedIndex = indexPath
        collectionView.reloadData()
        if autoHide {
            self.hide(hideAnimated) {[weak self] in
                guard let self = self else { return }
                self.delegate?.dropDownMenu(self, didClickAt: indexPath)
            }
        } else {
            self.delegate?.dropDownMenu(self, didClickAt: indexPath)
        }
    }

}
